#include "math.h"
#include "Texture2.h"

#ifndef PI
#define PI 3.1415926535
#endif

float NoiseGen::smoothNoise(float x, float y) {
    float fractX = x - (int) x;
    float fractY = y - (int) y;

    unsigned int x1 = ((int) x + width) % width;
    unsigned int y1 = ((int) y + height) % height;

    if (y1 > height) {
        y1 = height - 1;
    }
    if (x1 > height) {
        x1 = height - 1;
    }

    unsigned int x2 = (x1 + width - 1) % width;
    unsigned int y2 = (y1 + height - 1) % height;


    float value = 0.0;

    value += fractX * fractY * n[x1][y1];
    value += fractX * (1.0 - fractY) * n[x1][y2];
    value += (1.0 - fractX) * fractY * n[x2][y1];
    value += (1.0 - fractX) * (1.0 - fractY) * n[x2][y2];

    return value;
}

float NoiseGen::sample(int x, int y) {
    return n[x][y];    
}

float NoiseGen::turbulence(float x, float y, float size) {
    float value = 0.0;
    int i = size;

    while (i >= 1) {
        value += smoothNoise(x / i, y / i) * i;
        i /= 2.0;
    }

    return (value / size) / 2.0;
}

vec3 perlin1(float x, float y, vec3 pos, NoiseGen *noise) {
    vec3 fixNormal;

    fixNormal.x = (y / 8) + (x / 8) + 
                  noise->turbulence(x, y, 32.0) * 20.0;
    fixNormal.y = 0.1;
    fixNormal.z = (sin(fixNormal.x * PI)) / 4.0;
    fixNormal.x = (sin(fixNormal.x * PI)) / 4.0;

    return fixNormal;
}

vec3 perlin2(float x, float y, vec3 pos, NoiseGen *noise) {
    vec3 fixNormal;

    x /= 30.0;
    y /= 30.0;
    fixNormal.x = x + 9 * noise->turbulence(x, y, 16.0);
    fixNormal.y = y + 9 * noise->turbulence((512 - y), (512 - x), 16.0);
    fixNormal.z = 2 * fabs(sin(2 * fixNormal.x * PI) +
                            sin(2 * fixNormal.y * PI));
    fixNormal.x = fixNormal.z;
    fixNormal.y = 0.0;

    return fixNormal;
}

vec3 perlin3(float x, float y, vec3 pos, NoiseGen *noise) {
    vec3 fixNormal;

    fixNormal.x = x / 80.0;
    fixNormal.y = y / 80.0;
    fixNormal.z = sqrt(fixNormal.x * fixNormal.x + fixNormal.y * fixNormal.y) +
        noise->turbulence(y, x, 32) * 0.5;
    fixNormal.x = fabs(sin(4.5 * fixNormal.x * fixNormal.z * PI));
    fixNormal.y = 0.01;
    fixNormal.z = 0.100 + fixNormal.x;
    fixNormal.x += 0.10;

    return fixNormal;
}
